Depth Buffer和Uniform Buffer在OpenGL也有对应的概念,可以参考OpenGL的讲述来理解这两个缓冲区的作用。
Depth Buffer
本章节代码在06-init_depth_buffer.cpp
文件中。
Create a Depth Buffer
深度缓冲区(Depth Buffer)可以可选的,在最后的样例工程中要渲染3D立方体,就必须使用深度缓冲区。深度缓冲区对于每个Swapchain的Image都是可以复用的,因此,深度缓冲区应当只使用一个,即便Swapchain中有很多image对象。
不同于vkCreateSwapchainKHR()
,当Swapchain的每个Image对象创建时,你需要自己去创建和分配深度缓冲区给Image:
- 创建使用深度缓冲区Image对象
- 深度缓冲区所在设备上分配内存
- 把申请的内存绑定到Image对象上
- 创建使用深度缓冲区的Image View
以上步骤可以使用下图表示:
Create the Depth Buffer Image Object
与之前一些使用CreateInfo
创建对象的过程相同,创建使用深度缓冲区的Image对象的代码如下:
上面这份代码仅仅为Image创建了一个对象,还并没有为它申请深度缓冲区内存。但在创建时,你需要设置足够的信息用于创建匹配窗口大小的深度缓冲区。
Allocate the Memory for the Depth Buffer
在申请分配深度缓冲区内存之前,我们需要知道要申请的内存大小。但由于GPU硬件上的内存有对齐约束,而这些约束不同设备之间可能有所不同,因此,我们需要通过Vulkan的API来查询我们需要的内存大小、对齐方式、内存类型等信息:
然后我们需要用获取到的VkMemoryRequirements
对象,来填充VkMemoryAllocateInfo
这个Info对象:
memory_type_from_properties()
是一个用于确定适合的内存指针类型的函数。最后,使用下面的代码来进行分配内存:
Bind the Memory to the Depth Buffer
在拥有一个Image对象且申请到了设备上的深度缓冲区内存之后,就可以将缓冲区内存帮到Image对象上:
Create the Image View
接下来就是按照自己的需要,设置ViewCreateInfo对象,然后与之前相同的流程,使用vkCreateImageView()
函数创建对象:
Uniform Buffer
本章节代码在07-init_uniform_buffer.cpp
文件中。
Create a Uniform Buffer
Uniform Buffer是用来为着色器(shaders)程序提供常量数据的只读缓冲区。与深度缓冲区相同,你需要自己申请内存并填充它。
Setting up the Uniform Data
本章样例中,我们使用Uniform Buffer将MVP(Model-View-Projection)矩阵送到着色器中,如此着色器才能对每一个顶点进行转换。
下面是创建MVP矩阵的代码:
注意,
glm
库在这里用来简化代码,实际上矩阵运算需要自己写;info.MVP
是一个4*4的矩阵。
Creating the Uniform Buffer Object
创建Uniform缓冲区的过程与之前的深度缓冲区(Depth Buffer)基本一致,只有在usage
属性上有所不同:
Allocating the Uniform Buffer Memory
与为深度缓冲区申请内存使的过程一样,先使用API计算出需要的内存大小,然后使用memory_type_from_properties()
进行分配:
使用VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
标记,表示分配的这块内存对CPU(Host)是可以读取的。
使用VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
标记,表示Host的内存与设备是相互可见的,并不需要刷新内存缓存。这种做法对程序是一种简化,如此便不需要调用vkFlushMappedMemoryRanges
和vkInvalidateMappedMemoryRanges
来确保内存的数据对GPU可见。
Mapping and Setting the Uniform Buffer Memory
在使用深度缓冲区内存时,我们不需要去初始化它,这是因为GPU会对它的读写进行适当的处理。但在使用Uniform Buffer时,我们必须用我们要传给着色器的数据来填充它。为了让CPU能够对Uniform Buffer的内存进行读写,我们需要进行如下映射:
然后将数据复制到Uniform BUffer上,再解除映射:
由于这块缓冲区在内存上,进行内存映射会由于页表替换等导致映射无效,因此需要立即解除映射。
最后,你只需要创建一个Buffer对象来关联内存:
然后,Unform Buffer就算可以使用了。
本篇Vulkan Samples Tutorial原文是LUNAEXCHANGE中的Vulkan Tutorial的译文。
并非逐字逐句翻译,如有错误之处请告知。O(∩_∩)O谢谢~~